package com.king.juc.biased;

import lombok.extern.slf4j.Slf4j;
import org.openjdk.jol.info.ClassLayout;

import java.util.Vector;
import java.util.concurrent.locks.LockSupport;

/**
 * 偏向锁 demo, 查看对象信息(引入 jol-core 包)
 * |--------------------------------------------------------------------------------------------|
 * |                      Mark word(64 bits)                              |         State       |
 * | -------------------------------------------------------------------- | ------------------- |
 * | unused: 25 | hashcode: 31 | unused: 1 | age: 4 | biased_lock: 0 | 01 |       Normal        |
 * | thread: 54 | epoch: 2     | unused: 1 | age: 4 | biased_lock: 1 | 01 |       Biased        |
 * | ptr_to_lock_record: 62                                          | 00 | Lightweight Locked  |
 * | ptr_to_heavyweight_monitor: 62                                  | 10 | Heavyweight Locked  |
 * |                                                                 | 11 | Marked for GC       |
 * |--------------------------------------------------------------------------------------------|
 * <p>
 * 偏向锁 > 轻量级锁 > 重量级锁
 * -XX:BiasedLockingStartupDelay=0 偏向锁延时, 系统启动 X 秒后启用偏向锁
 * -XX:-UseBiasedLocking   '-' 为禁用偏向锁
 *
 * @author king
 * @date 2020/10/30 23:15
 */
@Slf4j(topic = "c.Biased")
public class Biased {
    public static void main(String[] args) {
//        revoke1();
//        revoke2();
//        revoke3();
//        batchReBias();
        batchRevocation();
    }

    /**
     * 撤销偏向锁情况一
     */
    public static void revoke1() {
        Object o = new Object();
        // 撤销对象可偏向状态, 当一个可偏向的对象调用 hashCode() 之后, 就会撤销该对象的偏向状态(偏向状态没有额外存储空间)
        o.hashCode();

        // 多个线程访问同一个变量导致线程撤销
        log.debug(ClassLayout.parseInstance(o).toPrintable());

        synchronized (o) {
            log.debug(ClassLayout.parseInstance(o).toPrintable());
        }

        log.debug(ClassLayout.parseInstance(o).toPrintable());
    }

    /**
     * 撤销偏向锁情况二
     */
    public static void revoke2() {
        Object o = new Object();
        // 多个线程访问同一个变量导致线程撤销
        new Thread(() -> {

            log.debug(ClassLayout.parseInstance(o).toPrintable());

            synchronized (o) {
                log.debug(ClassLayout.parseInstance(o).toPrintable());
            }

            log.debug(ClassLayout.parseInstance(o).toPrintable());

            // 错开访问同一个对象的时间
            synchronized (Biased.class) {
                Biased.class.notify();
            }
        }, "t1").start();

        // 从原先的 101 可偏向变成 001 不可偏向
        new Thread(() -> {
            // 错开访问同一个对象的时间
            synchronized (Biased.class) {
                try {
                    Biased.class.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            log.debug(ClassLayout.parseInstance(o).toPrintable());

            synchronized (o) {
                log.debug(ClassLayout.parseInstance(o).toPrintable());
            }

            log.debug(ClassLayout.parseInstance(o).toPrintable());
        }, "t2").start();
    }

    /**
     * 撤销偏向锁情况三
     */
    public static void revoke3() {
        // wait() / notify(), 调用该方法会升级成重量级锁

    }

    /**
     * 批量重偏向
     *      阈值: 20
     *      问题: 到17就开始重偏向了, 具体原因待检查
     */
    public static void batchReBias(){
        Vector<Object> list = new Vector<>();
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 30; i++) {
                Object o = new Object();
                list.add(o);
                synchronized (o) {
                    log.debug(i + "\t" + ClassLayout.parseInstance(o).toPrintable());
                }
            }
            synchronized (list) {
                list.notify();
            }
        }, "t1");
        t1.start();

        Thread t2 = new Thread(() -> {
            synchronized (list){
                try {
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            log.debug("========================================================================================\n");
            for (int i = 0; i < 30; i++) {
                Object o = list.get(i);
                log.debug(i + "加锁前\n" + ClassLayout.parseInstance(o).toPrintable());
                synchronized (o) {
                    log.debug(i + "加锁中\n" + ClassLayout.parseInstance(o).toPrintable());
                }
                log.debug(i + "加锁后\n" + ClassLayout.parseInstance(o).toPrintable());
            }
        }, "t2");
        t2.start();
    }


    static Thread t1, t2, t3;
    /**
     * 批量撤销
     *      阈值: 40
     *      超过阈值之后, 整个类的所有对象都变为不可偏向, 新建的对象也是不可偏向的
     */
    public static void batchRevocation(){
        Vector<Object> list = new Vector<>();
        int loopNumber = 39;
        t1 = new Thread(() -> {
            for (int i = 0; i < loopNumber; i++) {
                Object o = new Object();
                list.add(o);
                synchronized (o){
                    log.debug(i + "\t" + ClassLayout.parseInstance(o).toPrintable());
                }
            }
            LockSupport.unpark(t2);
        }, "t1");
        t1.start();

        t2 = new Thread(() -> {
            LockSupport.park();
            log.debug("=================================================================");
            for (int i = 0; i < loopNumber; i++) {
                Object o = list.get(i);
                log.debug(i + "加锁前\n" + ClassLayout.parseInstance(o).toPrintable());
                synchronized (o) {
                    log.debug(i + "加锁中\n" + ClassLayout.parseInstance(o).toPrintable());
                }
                log.debug(i + "加锁后\n" + ClassLayout.parseInstance(o).toPrintable());
            }
            LockSupport.unpark(t3);
        }, "t2");
        t2.start();

        t3 = new Thread(() -> {
            LockSupport.park();
            log.debug("=================================================================");
            for (int i = 0; i < loopNumber; i++) {
                Object o = list.get(i);
                log.debug(i + "加锁前\n" + ClassLayout.parseInstance(o).toPrintable());
                synchronized (o) {
                    log.debug(i + "加锁中\n" + ClassLayout.parseInstance(o).toPrintable());
                }
                log.debug(i + "加锁后\n" + ClassLayout.parseInstance(o).toPrintable());
            }
        }, "t3");
        t3.start();

        try {
            t3.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.debug(ClassLayout.parseInstance(new Object()).toPrintable());
    }
}
